`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Design Name: Kevin Zhang
// Module Name: test_verify_mod
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module FIFO_sync #(
	parameter    DATA_WIDTH    = 32,
                 ADDRESS_WIDTH = 2,
                 FIFO_DEPTH    = (1 << ADDRESS_WIDTH)
                 )
     //Reading port
    (output reg  [DATA_WIDTH-1:0]        Data_out, 
     output reg                          Empty_out,
     input wire                          Rd_en,       
     //Writing port.	 
     input wire  [DATA_WIDTH-1:0]        Data_in,  
     output reg                          Full_out,
     input wire                          Wr_en,

     input wire                          Clk, 	 
     input wire                          Rst_n);

    /////Internal connections & variables//////
    reg   [DATA_WIDTH-1   :0]           Mem [FIFO_DEPTH-1:0]; 
    reg   [ADDRESS_WIDTH  :0]           Rd_pt, Wr_pt;
    wire  [ADDRESS_WIDTH-1:0]           Rd_addr, Wr_addr;


    assign Rd_addr = Rd_pt[ADDRESS_WIDTH-1:0];
    assign Wr_addr = Wr_pt[ADDRESS_WIDTH-1:0];
    
    //////////////Code///////////////
    always @ (posedge Clk) 
    begin:Data_out_latch
        if (Rd_en & !Empty_out) 
            Data_out <= Mem[Rd_addr];
    end
            
    //'Data_in' logic:
    always @ (posedge Clk)
    begin:Data_in_logic   
        if (Wr_en & !Full_out) 
            Mem[Wr_addr] <= Data_in;
    end

    always @ (posedge Clk or negedge Rst_n)
    begin:Rd_pt_latch
        if (!Rst_n) 
            Rd_pt <= 3'b0;  
        else if (Rd_en & !Full_out) 
            Rd_pt <= Rd_pt + 1'b1;
    end

    always @ (posedge Clk or negedge Rst_n)
    begin:Wr_pt_latch
        if (!Rst_n) 
            Wr_pt <= 3'b0;  
        else if (Wr_en & !Full_out)
            Wr_pt <= Wr_pt + 1'b1;
    end

    //full & empty ctrl
    always @ (posedge Clk or negedge Rst_n)
    begin:Full_out_logic
        if (!Rst_n)
            Full_out <= 1'b0;
        else if ((Wr_pt[2] != Rd_pt[2]) && (Wr_addr == Rd_addr))
            Full_out <= 1'b1;
        else
            Full_out <= 1'b0;
    end

    always @ (posedge Clk or negedge Rst_n)
    begin:Empty_out_logic
        if (!Rst_n)
            Empty_out <= 1'b1;
        else if (Wr_pt == Rd_pt)
            Empty_out <= 1'b1;
        else
            Empty_out <= 1'b0;
    end

endmodule